using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Text.Json;



namespace FTIOT_CAT1
{
    public partial class Form1 : Form
    {
        private SerialPort? serialPort = null; // 将 serialPort 声明为可空类型
        private SensorTypeLis sensorTypeLis = new(); // 初始化传感器类型列表
        private SensorTypeLis sensorTypeStandardLis = new(); // 初始化标准传感器类型列表
        public SensorList sensorList = new(""); // 初始化选中的传感器列表

        private DataGridViewList dataGridViewList = new(); // 传感器excel列表
        private AutoResetEvent messageEvent = new AutoResetEvent(false);
        private ToolTip toolTip1 = new ToolTip();
        private ConfigurationGeneration configurationGeneration = new();// 初始化配置生成器
        private const string Xlsx = "..//传感器点表//sensor485List.xlsx";
        private const string aesKey = "2b7e151628aed2a6abf7158809cf4f3c"; // 与 textAes.cpp 相同的 AES 密钥（16 字节的 HEX 表示）

        public Form1()
        {
            InitializeComponent();
            Init();
        }
        public static class SerialPortGlobalData
        {
            public static int BAUDRATE = 9600; // 默认波特率
            public static int DATABITS = 8; // 默认数据位
            public static StopBits STOPBITS = StopBits.One; // 默认停止位
            public static StopBits STOPBITS_ = StopBits.One; // 默认停止位
            public static Parity PARITYBITS = Parity.None; // 默认校验位
            public static Handshake HANDSHAKE = Handshake.None; // 默认流控制
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)// 窗口即将关闭时触发删除生成的文件
        {
            // 删除运行生成的文件
            try
            {
                string filePath = Path.GetFullPath("sensorList.json");
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                filePath = Path.GetFullPath("CONFIG.txt");
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
            catch (Exception ex)
            {
                // 可选：记录或提示删除失败
                Debug.WriteLine("文件删除失败: " + ex.Message);
            }

        }

        private void Form1_ResizeBegin(object sender, EventArgs e)//窗口大小改变时，暂停布局更新以提高性能
        {
            this.SuspendLayout();
            foreach (Control ctrl in this.Controls)
            {
                ctrl.SuspendLayout();
            }
        }

        private void Form1_ResizeEnd(object sender, EventArgs e)//窗口大小改变停止时，布局更新以提高性能
        {
            foreach (Control ctrl in this.Controls)
            {
                ctrl.ResumeLayout(false);
            }
            this.ResumeLayout(true);
        }

        private void Init()//进入界面后执行的初始化操作
        {
            SerialPortComboBox.Focus();
            comboBox4GLED.SelectedIndex = 0; // 默认选择第一个LED显示方式
            comboBoxScreenHeight.SelectedIndex = 1; // 默认选择第一个屏幕高度
            comboBoxScreenWidth.SelectedIndex = 1; // 默认选择第一个屏幕宽度
            Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);//导入GB2312
            UpdateSerialPortList();
            ReadExcelFile(Xlsx);//读取传感器信息
            FillSensorDataGridView();
            AddSensorToDataGridView(null); // 将选中的传感器添加到 dataGridView1 中
            AddInstrument();//添加小工具
            ComponentHoverPrompt();// 组件悬停提示
            shouchiBaud.SelectedIndex = 3; // 默认选择第4个选项
            //如果没有cachefile/cache目录则创建
            if (!Directory.Exists("cachefile"))
            {
                Directory.CreateDirectory("cachefile");
            }
        }

        private void ComponentHoverPrompt()// 组件悬停提示
        {
            toolTip1.SetToolTip(buttonSingleConfig, "点击此按钮配置单机软件Modbus功能,右键单击生成传感器点表");
            toolTip1.SetToolTip(buttonSingleConfig2, "点击此按钮配置单机软件Json功能");
            toolTip1.SetToolTip(button4GConfig, "点击此按钮配置4G采集器参数");
            toolTip1.SetToolTip(buttonConfigLED, "点击此按钮配置LED屏参数");
            toolTip1.SetToolTip(buttonEmptyData, "点击此按钮清空接收区域数据");
            toolTip1.SetToolTip(buttonReadData, "点击此按钮读取传感器数据");
            toolTip1.SetToolTip(buttonSetAddr, "点击此按钮设置传感器地址");
            toolTip1.SetToolTip(numericUpDownAddr, "设备当前地址");
            toolTip1.SetToolTip(numericUpDown1, "设备修改后的地址");
            toolTip1.SetToolTip(button1, "取消选中的传感器");
            toolTip1.SetToolTip(SerialPortSettingButton, "设置串口的详细信息");
            toolTip1.SetToolTip(comboBoxScreenWidth, "屏幕横向的灯板数量");
            toolTip1.SetToolTip(comboBoxScreenHeight, "屏幕竖向的灯板数量");
            toolTip1.SetToolTip(standardComboBox, "选择标准品传感器");
        }

        private void toolStripMenuItem_Click(object? sender, EventArgs e) // 单击传感器列表时发生
        {
            ToolStripMenuItem? toolStripMenuItem = sender as ToolStripMenuItem; // 将 sender 转换为 ToolStripMenuItem
            if (toolStripMenuItem != null && toolStripMenuItem.Tag != null)
            {
                string fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, toolStripMenuItem.Tag.ToString() ?? "");// 获取完整路径  
                if (File.Exists(fullPath))
                {
                    var startInfo = new ProcessStartInfo
                    {
                        FileName = fullPath,
                        WorkingDirectory = Path.GetDirectoryName(fullPath),
                        UseShellExecute = true
                    };
                    Process.Start(startInfo);
                }
                else
                {
                    MessageBox.Show("指定的程序不存在！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        private void AddInstrument()//添加小工具
        {
            //打开上一级目录下的“instrument”文件夹
            string instrumentPath = Path.Combine("..\\instrument");
            if (Directory.Exists(instrumentPath)) // 检查目录是否存在
            {
                toolStripMenuItem1.DropDownItems.Clear(); // 清空下拉菜单
                //获取所有的子文件夹
                string[] directories = Directory.GetDirectories(instrumentPath); // 获取所有的子目录
                foreach (string dir in directories)
                {
                    if (Directory.Exists(dir))
                    {
                        string dirName = Path.GetFileName(dir); // 获取目录名
                        ToolStripMenuItem toolStripMenuItem = new ToolStripMenuItem(dirName);
                        toolStripMenuItem1.DropDownItems.Add(toolStripMenuItem); // 添加到下拉菜单中
                        string[] files = Directory.GetFiles(dir, "*.exe"); // 获取所有的exe文件
                        foreach (string file in files)
                        {
                            string fileName = Path.GetFileNameWithoutExtension(file); // 获取文件名（不带扩展名）
                            ToolStripMenuItem toolStripMenuItem2 = new ToolStripMenuItem(fileName);
                            toolStripMenuItem2.Tag = file; // 将文件路径存储在 Tag 属性中
                            toolStripMenuItem2.Click += toolStripMenuItem_Click; // 添加点击事件
                            toolStripMenuItem.DropDownItems.Add(toolStripMenuItem2); // 添加到下拉菜单中
                        }
                    }
                }
            }
        }


        private bool isSerialPortOpen()// 判断串口是否打开
        {
            return (serialPort != null && serialPort.IsOpen);
        }
        private void SerialPortOpenButton_Click(object sender, EventArgs e)//单击打开串口按钮时发生
        {
            if (SerialPortOpenButton.Text == "打开")
            {
                try
                {
                    if (!isSerialPortOpen())
                    {
                        if (SerialPortComboBox.SelectedItem == null || string.IsNullOrEmpty(SerialPortComboBox.SelectedItem.ToString()))
                        {
                            throw new InvalidOperationException("没有找到串口！！");
                        }
                        serialPort = new SerialPort(SerialPortComboBox.SelectedItem.ToString())
                        {
                            BaudRate = SerialPortGlobalData.BAUDRATE, // 设置默认波特率
                            DataBits = SerialPortGlobalData.DATABITS, // 数据位
                            StopBits = SerialPortGlobalData.STOPBITS, // 停止位
                            Parity = SerialPortGlobalData.PARITYBITS, // 校验位
                            Handshake = SerialPortGlobalData.HANDSHAKE // 流控制
                        };
                        serialPort.DataReceived += SerialPort_DataReceived; // 绑定接收事件
                        serialPort.Open(); // 打开串口
                        // 打印连接参数
                        Debug.WriteLine($"当前的波特率: {SerialPortGlobalData.BAUDRATE}");
                        Debug.WriteLine($"当前的数据位: {SerialPortGlobalData.DATABITS}");
                        Debug.WriteLine($"当前的停止位: {SerialPortGlobalData.STOPBITS}");
                        Debug.WriteLine($"当前的校验位: {SerialPortGlobalData.PARITYBITS}");
                        Debug.WriteLine($"当前的流控制: {SerialPortGlobalData.HANDSHAKE}");

                        SerialPortOpenButton.Text = "关闭";
                        SerialPortComboBox.Enabled = false; // 禁用串口下拉框
                        SerialPortSettingButton.Enabled = false; // 禁用串口设置按钮
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"连接失败：{ex.Message}");
                }
            }
            else // 关闭串口
            {
                try
                {
                    if (serialPort != null)
                    {
                        serialPort.Close(); // 关闭串口
                        serialPort.Dispose(); // 释放串口资源
                        serialPort = null; // 将 serialPort 设置为 null
                        SerialPortOpenButton.Text = "打开";
                        SerialPortComboBox.Enabled = true; // 重新启用串口下拉框
                        SerialPortSettingButton.Enabled = true; // 重新启用串口设置按钮
                    }

                }
                catch (Exception ex)
                {
                    MessageBox.Show($"关闭失败：{ex.Message}");
                }
            }

        }

        public byte[] InversionBytes(byte[] data) //数组倒转  
        {
            if (data == null)
            {
                return data ?? []; // 如果数据为空或长度小于2，返回空数组而不是 null  
            }
            byte[] swappedData = new byte[data.Length];

            for (int i = 0; i < data.Length; i++)
            {
                swappedData[i] = data[data.Length - i - 1]; // 将相邻的两个字节交换位置  
            }
            return swappedData;
        }

        public void AnalysisModbusData(byte[] bytes)//Modbus数据解析
        {
            string dataType = textBoxDataType.Text;// 数据类型
            int decimals = 0;// 小数位数
            string displayData = ""; // 用于显示的数据
            if (textBoxSensor.Tag == null) return; // 确保 textBoxSensor.Tag 不为 null
            Sensor sensor = (Sensor)textBoxSensor.Tag; // 从 textBoxSensor 的 Tag 属性中获取传感器对象
            if (bytes.Length < 7 || bytes[0] != (byte)numericUpDownAddr.Value || sensor == null) return; // 确保数据长度足够和地址对应
            //提取textBoxDataType.Text中的数字

            foreach (char c in textBoxDataType.Text)// 匹配字母和数字部分
            {
                if (c >= '0' && c <= '9')
                {
                    decimals = c - '0';
                    break; // 如果是数字或小数点，跳出循环
                }
            }
            byte[] crc = ModbusUtils.CalculateCRC(bytes, bytes.Length - 2);
            if (bytes[^2] == crc[0] && bytes[^1] == crc[1])
            {
                byte[] dataBytes = new byte[bytes[2]]; // 3个字节是地址和功能码
                Array.Copy(bytes, 3, dataBytes, 0, bytes[2]); // 从第4个字节开始复制数据
                switch (dataType[1])
                {
                    case 'a'://DCBA
                        for (int j = 0; j < bytes[2]; j++)
                            dataBytes[j] = bytes[bytes[3 + j]];
                        break;
                    case '.':
                    case 'd'://ABCD
                        dataBytes = InversionBytes(dataBytes);
                        break;
                    case 'b'://CDAB
                        for (int j = 0; j < bytes[2]; j++)
                            if (j % 2 == 0) dataBytes[j] = bytes[3 + j + 1];//只交换字节序
                            else dataBytes[j] = bytes[3 + j - 1];
                        break;
                    case 'c'://BADC
                        {
                            byte[] tempBytes = new byte[bytes[2]];
                            Array.Copy(dataBytes, tempBytes, bytes[2]);
                            for (int j = 0; j < bytes[2] / 2; j++)
                                dataBytes[j] = tempBytes[bytes[2] / 2 - j - 1];//只交换字序
                        }
                        break;
                }
                switch (dataType[0])
                {
                    case 'i':
                        //dataBytes = InversionBytes(dataBytes);
                        int ivalue = dataBytes.Length switch
                        {
                            2 => BitConverter.ToInt16(dataBytes, 0),
                            4 => BitConverter.ToInt32(dataBytes, 0),
                            _ => 0
                        };
                        displayData = (ivalue / Math.Pow(10, decimals)).ToString($"F{decimals}");
                        break;
                    case 'n':
                        //dataBytes = InversionBytes(dataBytes);
                        uint uvalue = dataBytes.Length switch
                        {
                            2 => BitConverter.ToUInt16(dataBytes, 0),
                            4 => BitConverter.ToUInt32(dataBytes, 0),
                            _ => 0
                        };
                        displayData = (uvalue / Math.Pow(10, decimals)).ToString($"F{decimals}");
                        break;
                    case 'f': // 32位浮点数
                        displayData = BitConverter.ToSingle(dataBytes, 0).ToString($"F{decimals}");
                        break;
                    case 'd': // 64位浮点数
                        displayData = BitConverter.ToDouble(dataBytes, 0).ToString($"F{decimals}");
                        break;
                }
                // 显示数据到文本框
                textBoxData.Text = displayData;
            }
        }

        private bool JudgeHEX(byte[] buff)//判断是不是可见字符
        {
            foreach (var b in buff)
            {
                if (b < 0x0A) // 检查是否为可打印字符
                {
                    return true; // 如果有不可打印字符，返回 true
                }
            }
            return false;
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)// 接收数据
        {
            Invoke(new Action(() =>
            {
                timer1.Stop(); // 停止定时器
                timer1.Start(); // 启动定时器
            })); // 使用 Invoke 方法在 UI 线程上执行
        }
        private void timer1_Tick(object sender, EventArgs e)//定时器触发事件防止串口接收不完全
        {
            string strData = "";
            timer1.Enabled = false;
            if (serialPort != null) // 检查 serialPort 是否为 null
            {
                byte[] buff = new byte[serialPort.BytesToRead]; // 创建一个字节数组来存储接收到的数据
                serialPort.Read(buff, 0, buff.Length); // 读取串口数据到字节数组

                Invoke(new Action(() =>
                {
                    if (JudgeHEX(buff))// 判断是否是16进制字符串
                    {
                        if (buff.Length >= 7 && buff[1] == 0x03)//检查字符串是否是Modbus数据
                            AnalysisModbusData(buff);// 解析Modbus数据
                        strData = buff.Length > 0 ? BitConverter.ToString(buff).Replace("-", " ") : ""; // 将字节数组转换为字符串
                    }
                    else
                    {
                        strData = Encoding.UTF8.GetString(buff);
                        if (strData.Contains("ok"))
                            messageEvent.Set(); // 触发信号
                    }
                    sendTxt.AppendText(strData); // 显示到文本框
                    if (sendTxt.Lines.Length > 0)//获取staetTxt最后一行的数据
                        sendTxt.AppendText(Environment.NewLine); // 显示到文本框 
                }));
            }
        }
        private void UpdateSerialPortList()// 更新串口列表并保持当前选择（如果可用）
        {
            try
            {
                string? previousSelection = SerialPortComboBox.SelectedItem?.ToString();
                // 获取并排序串口列表
                string[] ports = SerialPort.GetPortNames();

                // 更新下拉列表
                SerialPortComboBox.Items.Clear();
                SerialPortComboBox.Items.AddRange(ports);

                // 恢复之前已选择的串口（如果仍然可用）
                if (!string.IsNullOrEmpty(previousSelection) &&
                    SerialPortComboBox.Items.Contains(previousSelection))
                {
                    SerialPortComboBox.SelectedItem = previousSelection;
                }
                else if (SerialPortComboBox.Items.Count > 0)
                {
                    SerialPortComboBox.SelectedIndex = 0; // 默认选择第一个
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"更新串口列表时出错: {ex.Message}", "错误",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void SerialPortComboBox_SelectedIndexChanged(object sender, EventArgs e)//串口下拉框选择变化时触发
        {
            UpdateSerialPortList();
            Debug.WriteLine("更新串口列表");
        }

        private void SerialPortSettingButton_Click(object sender, EventArgs e)// 打开一个新的窗口来设置串口参数
        {
            // 打开一个新的窗口来设置串口参数
            SerialSettingFrom SerialSettingFrom = new SerialSettingFrom();
            SerialSettingFrom.ShowDialog();
        }

        private void buttonRefreshSensor_Click(object sender, EventArgs e)//刷新传感器列表
        {
            sensorTypeStandardLis = new SensorTypeLis(); // 清空标准传感器类型列表
            sensorTypeLis = new SensorTypeLis(); // 清空传感器类型列表
            ReadExcelFile(Xlsx);//读取传感器信息
            FillSensorDataGridView();
        }
        //新建DataGridView控件添加到groupBox2中，填充传感器信息

        public Sensor? ReadSensor(IRow row, int i) //读取传感器信息 将返回类型改为可空类型
        {
            try
            {
                // 检查行是否为空
                if (row.Cells.All(cell => cell.CellType == CellType.Blank))
                {
                    return null; // 跳过空行
                }
                // 读取每个单元格的数据，并处理可能的空值

                Sensor sensor = new(
                    deviceAddress: row.GetCell(0) != null && row.GetCell(0).CellType == CellType.Numeric ? (int)row.GetCell(0).NumericCellValue : 0,
                    name: row.GetCell(1)?.ToString() ?? "",
                    registerAddress: row.GetCell(2) != null && row.GetCell(2).CellType == CellType.Numeric ? (int)row.GetCell(2).NumericCellValue : 0,
                    registerLength: row.GetCell(3) != null && int.TryParse(row.GetCell(3).ToString(), out int regLen) ? regLen : 0,
                    dataType: row.GetCell(4)?.ToString() ?? "",
                    uploadName: row.GetCell(5)?.ToString() ?? "",
                    ledDisplay: row.GetCell(6)?.ToString() ?? "",
                    addressRegister: row.GetCell(7) != null && int.TryParse(row.GetCell(7).ToString(), out int addrReg) ? addrReg : 0,
                    category: row.GetCell(8)?.ToString() ?? "",
                    weight: row.GetCell(9) != null && row.GetCell(9).CellType == CellType.Numeric ? (int)row.GetCell(9).NumericCellValue : 0,
                    k: row.GetCell(10) != null && row.GetCell(10).CellType == CellType.Numeric ? (float)row.GetCell(10).NumericCellValue : 0,
                    b: row.GetCell(11) != null && row.GetCell(11).CellType == CellType.Numeric ? (float)row.GetCell(11).NumericCellValue : 0
                );

                // 检查并设置默认值
                if (sensor.Weight == 0) sensor.Weight = 10;
                if (sensor.Category == "") sensor.Category = "其他类";

                return sensor; // 返回传感器对象
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取行 {i} 时出错: {ex.Message}");
                return null; // 跳过有错误的行
            }
        }

        public void ReadExcelFile(string filePath)// 读取 Excel 文件
        {
            IWorkbook workbook;
            SensorTypeLis sensorTypeLisTs = new(); // 初始化传感器类型列表
            try
            {
                using var file = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                if (filePath.EndsWith(".xls"))
                {
                    workbook = new HSSFWorkbook(file);
                }
                else if (filePath.EndsWith(".xlsx"))
                {
                    workbook = new XSSFWorkbook(file);
                }
                else
                {
                    throw new Exception("不支持的文件格式");
                }

                ISheet sheet = workbook.GetSheetAt(0); // 读取第一个工作表
                                                       //ICell cell = sheet.GetRow(sheet.FirstRowNum).GetCell(0);
                                                       //sendTxt.Text+=cell.ToString();
                                                       // 遍历工作表中的每一行，从第二行开始（假设第一行是标题行）
                for (int i = sheet.FirstRowNum + 1; i <= sheet.LastRowNum; i++)
                {
                    IRow row = sheet.GetRow(i);
                    if (row == null) continue;
                    Sensor? sensor = ReadSensor(row, i);
                    if (sensor != null) // 检查 sensor 是否为 null
                    {
                        // 将传感器添加到传感器类型列表中
                        SensorList? sensorList = sensorTypeLisTs.GetSensorType(sensor.Category);
                        if (sensorList == null)
                        {
                            // 如果传感器类型列表中没有该类别
                            sensorList = new SensorList(sensor.Category);
                            sensorTypeLisTs.AddSensorType(sensorList);
                        }
                        sensorList.AddSensor(sensor);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取 Excel 文件时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return; // 如果读取失败，直接返回
            }

            // 按权重排序并填充 sensorTypeLis
            foreach (var srcList in sensorTypeLisTs.Sensors)
            {
                var destList = sensorTypeLis.GetSensorType(srcList.type) ?? new SensorList(srcList.type);
                if (!sensorTypeLis.Sensors.Contains(destList))
                    sensorTypeLis.AddSensorType(destList);
                else
                    destList.Sensors.Clear();

                // 按权重升序排序后批量添加
                foreach (var sensor in srcList.Sensors.OrderBy(s => s.Weight))
                    destList.AddSensor(sensor);
            }
            Re1adExcelFileStandard(workbook);// 在EXCEL表中读取“标准传感器”表
            //关闭文件
            workbook.Close();
        }
        private void Re1adExcelFileStandard(IWorkbook workbook) // 在EXCEL表中读取“标准传感器”表  
        {
            // 修复 CS1503 错误：GetSheetAt 方法需要一个整数索引，而不是字符串名称  
            int sheetIndex = workbook.GetSheetIndex("标准品"); // 获取工作表索引  
            SensorList? sensorList = null;
            if (sheetIndex == -1)
            {
                MessageBox.Show("未找到名为 '标准品' 的工作表", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            ISheet sheet = workbook.GetSheetAt(sheetIndex); // 使用索引获取工作表  
            if (sheet == null)
            {
                MessageBox.Show("无法读取工作表 '标准品'", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            standardComboBox.SelectedIndex = -1; // 清空下拉框的选中项
            standardComboBox.Text = ""; // 清空下拉框的文本
            standardComboBox.Items.Clear(); // 清空下拉框的所有项
            for (int i = sheet.FirstRowNum + 1; i <= sheet.LastRowNum; i++)
            {
                IRow row = sheet.GetRow(i);
                if (row == null) continue;
                string standard = row.GetCell(10)?.ToString() ?? "";
                Sensor? sensor = ReadSensor(row, i);
                if (!string.IsNullOrEmpty(standard))// 检查标准是否为空
                {
                    sensorList = sensorTypeStandardLis.GetSensorType(standard);
                    if (sensorList == null)
                    {
                        sensorList = new SensorList(standard);
                        sensorTypeStandardLis.AddSensorType(sensorList);
                    }
                    else
                    {
                        sensorList.Sensors.Clear();
                    }
                    if (!standardComboBox.Items.Contains(standard))
                    {
                        standardComboBox.Items.Add(standard);
                    }
                }
                if (sensor != null && sensorList != null)
                {
                    var sensorListTs = sensorTypeLis.GetSensorType(sensor.Category);
                    var sensorTs = sensorListTs?.Sensors.FirstOrDefault(s => s.Equalss(sensor, true));// 查找传感器列表里的传感器不检查KB
                    if (sensorTs != null)
                    {
                        sensorList.AddSensor(sensorTs);
                    }
                }
            }
        }

        private DataGridView NewDataGridView(String name)// 新建DataGridView控件存放列表中的传感器信息
        {
            DataGridView dataGridView = new DataGridView();
            // 清空现有的 DataGridView
            dataGridView.Rows.Clear();
            dataGridView.Columns.Clear();

            dataGridView.AllowUserToAddRows = false; // 禁止用户添加新行
            dataGridView.AllowUserToDeleteRows = false; // 禁止用户删除行
            dataGridView.ReadOnly = true; // 设置 DataGridView 为只读模式
            dataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect; // 设置选择模式为整行选择
            //禁止更改单元格大小
            dataGridView.AllowUserToResizeRows = false; // 禁止用户调整行高
            dataGridView.AllowUserToResizeColumns = false; // 允许用户调整列宽
            dataGridView.RowHeadersVisible = false;// 关闭行头显示

            dataGridView.Dock = DockStyle.Fill; // 填充父容器
            //添加单机事件
            dataGridView.CellMouseClick += dataGridView_CellMouseClick; // 添加单击事件处理程序
            dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill; // 自动填充列宽

            dataGridView.MultiSelect = false; // 禁止多选，确保每次只能选择一行

            //添加复选框列
            DataGridViewCheckBoxColumn checkBoxColumn = new()
            {
                Name = "Select",
                HeaderText = "选择",
                Width = 50, // 设置复选框列的宽度
                ReadOnly = true // 允许用户勾选复选框
            };
            dataGridView.Columns.Add(checkBoxColumn); // 添加复选框列

            // 添加列
            dataGridView.Columns.Add("DeviceAddress", "地址");
            dataGridView.Columns.Add("Name", "名称");

            dataGridView.Columns["Select"]!.Width = 40; // 设置设备地址列的宽度
            dataGridView.Columns["Select"]!.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;

            dataGridView.Columns["DeviceAddress"]!.Width = 40; // 设置设备地址列的宽度
            dataGridView.Columns["DeviceAddress"].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;

            dataGridView.Columns["Name"]!.Width = 100; // 设置名称列的宽度
            foreach (DataGridViewColumn column in dataGridView.Columns)//禁止自动排序
            {
                column.SortMode = DataGridViewColumnSortMode.NotSortable;
            }
            dataGridView.Name = name; // 设置 DataGridView 的名称
            dataGridViewList.AddSensorType(dataGridView); // 将 DataGridView 添加到列表中
            return dataGridView; // 返回新创建的 DataGridView
        }
        private void FillSensorDataGridView()//填充传感器信息到tableLayoutPanel2
        {
            // 填充数据
            if (dataGridViewList.GetSensorTypeCount() == 0)// 如果没有传感器列表
            {
                foreach (var sensorList in sensorTypeLis.Sensors)
                {
                    DataGridView dataGridView = NewDataGridView(sensorList.Sensors[0].Category);
                    foreach (var sensor in sensorList.Sensors)
                    {
                        int rowIndex = dataGridView.Rows.Add();
                        DataGridViewRow row = dataGridView.Rows[rowIndex];
                        row.Cells["DeviceAddress"].Value = sensor.DeviceAddress;
                        row.Cells["Name"].Value = sensor.Name;
                        row.Tag = sensor; // 将传感器对象存储在行的 Tag 属性中
                    }
                }
                // 清空原有的列样式
                tableLayoutPanel2.ColumnStyles.Clear();
            }

            tableLayoutPanel2.ColumnCount = dataGridViewList.GetSensorTypeCount(); // 设置表格列数为传感器类型数量
            for (int i = 0; i < tableLayoutPanel2.ColumnCount; i++)
            {
                tableLayoutPanel2.ColumnStyles.Add(
                    new ColumnStyle(SizeType.Percent, 100F / tableLayoutPanel2.ColumnCount)
                     );
            }

            // 将每个DataGridView添加到对应的列
            for (int i = 0; i < dataGridViewList.GetSensorTypeCount(); i++)
            {
                var dgv = dataGridViewList.dataGridView[i];
                Label label = new Label
                {
                    Text = dgv.Name,
                    TextAlign = ContentAlignment.MiddleCenter,
                    Dock = DockStyle.Fill,
                    Font = new Font("微软雅黑", 10, FontStyle.Bold)
                };
                // 避免重复添加
                if (tableLayoutPanel2.GetControlFromPosition(i, 1) == null)
                {
                    // 添加到tableLayoutPanel2的第1行，第i列
                    tableLayoutPanel2.Controls.Add(dgv, i, 1);
                    dgv.Dock = DockStyle.Fill; // 填充单元格
                    tableLayoutPanel2.Controls.Add(label, i, 0);
                    dgv.Rows[0].Selected = false;
                }
            }

        }

        private void AddSensorToDataGridView(Sensor? sensor)//添加选中的传感器到dataGridView1中
        {
            //将选中的传感器添加到dataGridView1中
            if (dataGridView1.Columns.Count == 0)
            {
                //将Sensor的属性全部添加到dataGridView1中
                dataGridView1.Columns.Add("DeviceAddress", "地址");
                dataGridView1.Columns.Add("Name", "名称");
                dataGridView1.Columns.Add("RegisterAddress", "寄存器地址");
                dataGridView1.Columns.Add("RegisterLength", "寄存器长度");
                dataGridView1.Columns.Add("DataType", "数据类型");
                dataGridView1.Columns.Add("LEDDisplay", "LED显示");
                dataGridView1.Columns.Add("UploadName", "上传名称");
                dataGridView1.Columns.Add("K", "K");
                dataGridView1.Columns.Add("B", "B");
                dataGridView1.Columns["DeviceAddress"]!.Width = 40; // 设置设备地址列的宽度
                dataGridView1.Columns["RegisterAddress"]!.Width = 75; // 设置设备地址列的宽度
                dataGridView1.Columns["RegisterLength"]!.Width = 75; // 设置设备地址列的宽度
                dataGridView1.Columns["DataType"]!.Width = 70; // 设置设备地址列的宽度

            }
            //遍历sensorList中的传感器
            if (sensor != null)
            {
                int rowIndex = dataGridView1.Rows.Add();
                DataGridViewRow newRow = dataGridView1.Rows[rowIndex];
                newRow.Cells["DeviceAddress"].Value = sensor.DeviceAddress;
                newRow.Cells["Name"].Value = sensor.Name;
                newRow.Cells["RegisterAddress"].Value = sensor.RegisterAddress;
                newRow.Cells["RegisterLength"].Value = sensor.RegisterLength;
                newRow.Cells["DataType"].Value = sensor.DataType;
                newRow.Cells["LEDDisplay"].Value = sensor.LEDDisplay;
                newRow.Cells["UploadName"].Value = sensor.UploadName;
                newRow.Cells["K"].Value = sensor.K;
                newRow.Cells["B"].Value = sensor.B;
                newRow.Tag = sensor;
            }
        }
        private void selectSensorCheckbox(bool select)// 选中传感器复选框
        {
            // 遍历 dataGridView1 中的所有行
            foreach (Sensor sensor in sensorList.Sensors)
            {
                // 在 dataGridViewList 中查找对应的传感器
                DataGridView dataGridView = dataGridViewList.GetGridViewList(sensor.Category);
                foreach (DataGridViewRow dgvRow in dataGridView.Rows)
                {
                    if (dgvRow.Tag is Sensor sensorInDGV && sensorInDGV.Equals(sensor))
                    {
                        dgvRow.Cells["Select"].Value = select; // 选中复选框
                        dgvRow.DefaultCellStyle.BackColor = select ? Color.LightBlue : Color.White; // 设置背景色为浅蓝色
                        break; // 找到对应的传感器后退出循环
                    }
                }
            }
        }

        private void cancelButton_Click(object sender, EventArgs e) //一键清除传感器
        {
            // 清空选中的传感器列表
            selectSensorCheckbox(false);// 选中传感器复选框
            //删除dataGridViewList1
            dataGridView1.Rows.Clear(); // 清空 dataGridView1 的所有行
            // 清空 sensorList
            sensorList.Sensors.Clear(); // 清空选中的传感器列表
        }

        private void standardComboBox_SelectedIndexChanged(object sender, EventArgs e)// 选中标准传感器
        {
            ComboBox? comboBox = sender as ComboBox;
            if (comboBox != null)
            {
                // 如果 comboBox 不为 null，获取选中的标准
                string selectedStandard = comboBox.SelectedItem?.ToString() ?? "";
                SensorList list = sensorTypeStandardLis.GetSensorType(selectedStandard);
                if (list == null) return;
                foreach (var sensor in list.Sensors)
                {
                    AddDelayRowsSensorList(dataGridView1, sensor); // 添加选中行
                }
            }
            selectSensorCheckbox(true);// 选中传感器复选框
        }
        private void dataGridView_CellMouseClick(object? sender, DataGridViewCellMouseEventArgs e)// 传感器列表的单击事件，显式允许 sender 参数为可空引用类型。
        {
            DataGridView? dataGridView = sender as DataGridView; // 使用可空类型的 DataGridView
            if (dataGridView == null || e.RowIndex < 0) return; // 处理 sender 为 null 的情况// 如果行索引小于0，直接返回，避免访问无效行

            DataGridViewRow row = dataGridView.Rows[e.RowIndex]; // 获取当前行
            bool isChecked = Convert.ToBoolean(row.Cells["Select"].Value);
            row.Cells["Select"].Value = !isChecked; // 切换复选框状态
            row.DefaultCellStyle.BackColor = !isChecked ? Color.LightBlue : Color.White; // 设置背景色
            if (row.Tag == null) return; // 确保 row.Tag 不为 null 再进行强制转换
            if (isChecked)
            {
                AddDelayRowsSensorList(dataGridView1, (Sensor)row.Tag, sensorList.Sensors.FindIndex(s => s.Equals((Sensor)row.Tag))); // 删除选中行
            }
            else
            {
                // 将选中的传感器添加到 sensorList
                AddDelayRowsSensorList(dataGridView1, (Sensor)row.Tag); // 添加选中行
                SensorParameterDisplay((Sensor)row.Tag); // 显示传感器参数
            }
            dataGridView.CurrentCell = null;// 清除当前单元格的选中状态
        }

        private void AddDelayRowsSensorList(DataGridView dataGridView, Sensor sensor, int index = -1)//添加和删除选中的传感器到dataGridView1中
        {
            if (index != -1)
            {
                // 获取当前行
                DataGridViewRow row = dataGridView.Rows[index];
                sensorList.RemoveSensor((Sensor?)row.Tag); // 从选中的传感器列表中移除
                dataGridView1.Rows.RemoveAt(index); // 删除选中行
            }
            else
            {
                if (sensorList.AddSensor(sensor))// 添加到选中的传感器列表中,添加成功返回true
                    AddSensorToDataGridView(sensor); // 将选中的传感器添加到 dataGridView1 中
            }
            dataGridView.ClearSelection();// 清除选中行
        }
        private void dataGridView1_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)// 传感器选中列表的双击事件
        {
            if (e.ColumnIndex == -1)//双击的是最左边一列 
            {
                //删除选中行
                if (e.RowIndex >= 0 && e.RowIndex < dataGridView1.Rows.Count)
                {
                    DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
                    // 将选中的传感器从 sensorList 中移除
                    Sensor? sensorToRemove = (Sensor?)row.Tag;
                    if (sensorToRemove != null)
                    {
                        DataGridView dataGridView = dataGridViewList.GetGridViewList(sensorToRemove.Category);
                        foreach (DataGridViewRow dgvRow in dataGridView.Rows)// 遍历 dataGridViewList 中的所有行，去除选中的传感器
                        {
                            if (dgvRow.Tag is Sensor sensor && sensor.Equals(sensorToRemove))
                            {
                                dgvRow.Cells["Select"].Value = false; // 取消选中复选框
                                dgvRow.DefaultCellStyle.BackColor = Color.White; // 恢复背景色
                                break; // 找到对应的传感器后退出循环
                            }
                        }
                        AddDelayRowsSensorList(dataGridView1, sensorToRemove, e.RowIndex); // 删除选中行
                    }
                }

            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)//搜索框输入搜索时发生
        {
            TextBox textBox = (TextBox)sender;
            //遍历dataGridViewList的所有DataGridView，查找包含搜索文本的传感器
            foreach (var sensorListTs in sensorTypeLis.Sensors)
            {
                DataGridView dataGridView = dataGridViewList.GetGridViewList(sensorListTs.Sensors[0].Category);
                dataGridView.Rows.Clear(); // 清空 DataGridView 所有行
                foreach (var sensor in sensorListTs.Sensors)
                {
                    // 如果传感器名称或上传名称或地址包含搜索文本，则添加到搜索结果列表
                    if (sensor.Name.Contains(textBox.Text, StringComparison.OrdinalIgnoreCase) ||
                        sensor.UploadName.Contains(textBox.Text, StringComparison.OrdinalIgnoreCase) ||
                        sensor.DeviceAddress.ToString() == textBox.Text)
                    {
                        int rowIndex = dataGridView.Rows.Add();
                        DataGridViewRow row = dataGridView.Rows[rowIndex];
                        row.Cells["DeviceAddress"].Value = sensor.DeviceAddress;
                        row.Cells["Name"].Value = sensor.Name;
                        row.Tag = sensor; // 将传感器对象存储在行的 Tag 属性中
                        if (sensorList?.Sensors.FirstOrDefault(s => s.Equals(sensor)) != null) // 确保传感器类型列表中包含该传感器
                        {
                            // 设置复选框为选中状态
                            row.Cells["Select"].Value = true; // 选中复选框
                            row.DefaultCellStyle.BackColor = Color.LightBlue; // 设置背景色为浅蓝色
                        }

                    }
                }
                if (dataGridView.Rows.Count != 0)
                {
                    dataGridView.Rows[0].Selected = false;// 清除当前单元格的选中状态
                }
            }

        }

        private void dataGridView1_RowsChange(object sender, DataGridViewRowsAddedEventArgs e)//选中传感器数量发生改变时发生
        {
            groupBox3.Text = "已选传感器列表(" + ((DataGridView)sender).RowCount + ")";
        }

        private void dataGridView1_RowsChange(object sender, DataGridViewRowsRemovedEventArgs e)//选中传感器数量发生改变时发生
        {
            groupBox3.Text = "已选传感器列表(" + ((DataGridView)sender).RowCount + ")";
        }

        private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)// 单元格值更改事件时发生
        {
            DataGridView? dataGridView = sender as DataGridView;
            if (dataGridView != null)
            {
                // 只有在单元格被编辑后才会触发此事件
                if (e.RowIndex < 0 || e.ColumnIndex < 0) return;
                // 获取当前行的传感器对象
                Sensor? oldSensor = (Sensor?)dataGridView.Rows[e.RowIndex].Tag;
                if (oldSensor == null) return; // 如果旧传感器对象为 null，直接返回
                // 创建一个新的传感器对象（可根据需要修改属性）
                Sensor newSensor = new(oldSensor);
                // 根据被编辑的列更新 newSensor 的属性
                // 简化后的 switch 处理
                var colName = dataGridView.Columns[e.ColumnIndex].Name;
                switch (colName)
                {
                    case "DeviceAddress":
                    case "RegisterAddress":
                    case "RegisterLength":
                        if (int.TryParse(e.Value?.ToString(), out int intValue))
                        {
                            if (colName == "DeviceAddress") newSensor.DeviceAddress = intValue;
                            else if (colName == "RegisterAddress") newSensor.RegisterAddress = intValue;
                            else if (colName == "RegisterLength") newSensor.RegisterLength = intValue;
                        }
                        else
                        {
                            e.ParsingApplied = false;
                        }
                        break;
                    case "K":
                    case "B":
                        if (float.TryParse(e.Value?.ToString(), out float floatValue))
                        {
                            if (colName == "K") newSensor.K = floatValue;
                            else if (colName == "B") newSensor.B = floatValue;
                        }
                        else
                        {
                            e.ParsingApplied = false;
                        }
                        break;
                    case "Name":
                        newSensor.Name = e.Value?.ToString() ?? "";
                        break;
                    case "DataType":
                        newSensor.DataType = e.Value?.ToString() ?? "";
                        break;
                    case "UploadName":
                        newSensor.UploadName = e.Value?.ToString() ?? "";
                        break;
                    case "LEDDisplay":
                        newSensor.LEDDisplay = e.Value?.ToString() ?? "";
                        break;
                }

                // 替换 sensorList 中的原对象
                int index = sensorList.Sensors.FindIndex(s => s.Equals(oldSensor));
                if (index == -1 || oldSensor.Equals(newSensor))
                    return; // 如果未找到或新旧传感器相同，则不进行更新
                sensorList.Sensors[index] = newSensor;
                // 同步 DataGridView 行的 Tag
                dataGridView.Rows[e.RowIndex].Tag = newSensor;
                //清除sensorTypeLis中相应的复选框为不选中
                DataGridView sensorDataGridView = dataGridViewList.GetGridViewList(oldSensor.Category);
                if (sensorDataGridView != null)
                {
                    foreach (DataGridViewRow row in sensorDataGridView.Rows)
                    {
                        if (row.Tag is Sensor sensor && sensor.Equals(oldSensor))
                        {
                            row.Cells["Select"].Value = false; // 取消选中复选框
                            row.DefaultCellStyle.BackColor = Color.White; // 恢复背景色
                            break; // 找到对应的传感器后退出循环
                        }
                    }
                }
            }
        }

        private void SensorParameterDisplay(Sensor sensor) //传感器参数显示
        {
            // 显示传感器信息到文本框
            textBoxSensor.Tag = sensor;
            textBoxSensor.Text = sensor.Name; // 显示传感器名称
            numericUpDownAddr.Value = sensor.DeviceAddress; // 显示设备地址
            numericUpDown1.Value = sensor.DeviceAddress; // 显示设备地址
            textBoxRegAddr.Text = sensor.RegisterAddress.ToString(); // 显示寄存器地址
            textBoxRegLen.Text = sensor.RegisterLength.ToString(); // 显示寄存器长度
            textBoxDataType.Text = sensor.DataType; // 显示数据类型
            textBoxUpName.Text = sensor.UploadName; // 显示上传名称
            textBoxDescribe.Text = sensor.LEDDisplay; // 显示LED显示
        }
        private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)//鼠标指针位于单元格边界内时按鼠标按钮时发生
        {

            DataGridView dataGridView = (DataGridView)sender; // 确保 sender 是 DataGridView 类型
            // 确保有行被选中
            if (dataGridView1.SelectedRows.Count > -1 && e.RowIndex > -1)
            {
                Sensor? sensor = (Sensor?)dataGridView.Rows[e.RowIndex].Tag; // 获取选中行的传感器对象
                if (sensor == null) return; // 如果传感器对象为 null，直接返回
                SensorParameterDisplay(sensor); // 显示传感器参数
            }
        }

        private void buttonConfig4GConfig_Click(object sender, EventArgs e)//单击配置4G传感器按钮时发生
        {
            Button button = (Button)sender;
            if (!isSerialPortOpen())
            {
                MessageBox.Show($"请打开串口");
                return;
            }
            messageEvent.Reset();//重置信号状态
            buttonConfig4GSensor.Enabled = false;
            buttonConfigScreen.Enabled = false;
            button43Screen.Enabled = false;
            Thread clientThread = new Thread(ConfigSensor);
            clientThread.IsBackground = true;
            clientThread.Start(button);

        }
        private String ObjectToString(Dictionary<string, object> data)//将字典对象转换为格式化的 JSON 字符串
        {
            try
            {
                // 配置 JSON 序列化选项（缩进）
                var options = new JsonSerializerOptions
                {
                    WriteIndented = false, // 启用缩进
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 可选：避免 Unicode 转义
                };
                // 重新序列化为格式化字符串
                //jsonString = JsonSerializer.Serialize(data, options);
                //Encoding gb2312 = Encoding.GetEncoding("GB2312");
                //bytesToSend = gb2312.GetBytes(jsonString);
                //return gb2312.GetString(bytesToSend);
                return JsonSerializer.Serialize(data, options); // 返回格式化的 JSON 字符串
            }
            catch (JsonException ex)
            {
                sendTxt.AppendText(ex.ToString());
                return "";
            }
        }

        private bool SerialSendData(String str)//串口发送字符串数据
        {
            if (serialPort != null && isSerialPortOpen())
            {
                try
                {
                    byte[] byteData = Encoding.GetEncoding("gb2312").GetBytes(str);//编码转换
                    serialPort.Write(byteData, 0, byteData.Length);
                    Invoke(new Action(() =>
                    {
                        sendTxt.AppendText(str + Environment.NewLine);
                    })); // 更新UI
                }
                catch (Exception e)
                {
                    ConfigButtonEnabled();//启用配置采集器的按钮
                    MessageBox.Show($"串口发送错误！: {e.Message}");
                    return false;
                }
            }
            else
            {
                MessageBox.Show("请先打开串口");
                return false;
            }

            return true;
        }
        private bool SerialSendData(byte[] str)//串口发送字符串数据
        {
            if (serialPort != null && isSerialPortOpen())
            {
                try
                {
                    serialPort.Write(str, 0, str.Length);
                    Invoke(new Action(() =>
                    {
                        sendTxt.AppendText(BitConverter.ToString(str).Replace("-", " ") + Environment.NewLine); // 显示到文本框 
                    })); // 更新UI
                }
                catch (Exception e)
                {
                    ConfigButtonEnabled();//启用配置采集器的按钮
                    MessageBox.Show($"串口发送错误！: {e.Message}");

                    return false;
                }
            }
            else
            {
                MessageBox.Show("请先打开串口");
                return false;
            }

            return true;
        }
        private void ConfigButtonEnabled()//启用配置采集器的按钮
        {
            Invoke(new Action(() =>
            {
                buttonConfig4GSensor.Enabled = true;
                buttonConfigScreen.Enabled = true;
                button43Screen.Enabled = true;
            })); // 更新UI  
        }

        private void ConfigSensor(object? obj)//创建一个发送串口数据的线程;配置采集器和屏幕
        {
            string jsonString;
            Button? button = obj as Button;
            if (button == null) return; // 确保 obj 是 Button 类型
            int delayT = int.TryParse(button.Tag?.ToString(), out int t) ? t : 0;
            foreach (DataGridViewRow newRow in dataGridView1.Rows)
            {
                Sensor? sensor = (Sensor?)newRow.Tag; // 获取传感器对象
                if (sensor == null) continue; // 如果传感器对象为 null，跳过
                if (!isSerialPortOpen())
                {
                    ConfigButtonEnabled();////启用配置采集器的按钮
                    return;
                }
                var data = new Dictionary<string, object>
                {
                    { "cmd", "add485Sensor" },
                    { "addr", sensor.DeviceAddress },
                    { "regAddr", sensor.RegisterAddress },
                    { "dataLen", sensor.RegisterLength },
                    { "valueType", sensor.DataType },
                    { "name", sensor.UploadName },
                    { "describe", sensor.LEDDisplay }
                };
                if (sensor.K != 0.0)
                {
                    data.Add("K", sensor.K);
                }
                if (sensor.B != 0.0)
                {
                    data.Add("B", sensor.B);
                }
                if (button.Name == "buttonConfigScreen")
                {
                    data.Add("dataType", "json");
                }
                jsonString = ObjectToString(data);// 将字典转换为 JSON 字符串

                if (button.Name == "buttonConfig4GSensor")
                {
                    int retry = 3;
                    while (retry-- > 0)
                    {
                        if (!SerialSendData(jsonString))
                        {
                            ConfigButtonEnabled();
                            return;
                        }
                        if (messageEvent.WaitOne(TimeSpan.FromMilliseconds(delayT)))// 等待200毫秒如果接收到响应则发送下一条数据
                            break;
                    }
                }
                else if (button.Name == "buttonConfigScreen" || button.Name == "button43Screen")
                {
                    if (!SerialSendData(jsonString))
                    {
                        ConfigButtonEnabled();
                        return;
                    }
                }
                Thread.Sleep(delayT);
            }
            ConfigButtonEnabled();
        }

        private void buttonSingleConfig_Click(object sender, EventArgs e)//单击配置单机软件按钮时发生
        {
            Button button = (Button)sender;
            if (sensorList.Sensors.Count == 0)
            {
                MessageBox.Show("请先选择传感器");
                return;
            }
            if (button.Tag == null) return;
            sendTxt.Text = "";
            ConfigSensor(0);
            configurationGeneration.JsonTransition((string)button.Tag, sensorList);
        }
        // 事件处理器
        private void button1_MouseDown(object? sender, MouseEventArgs e)//右键单击配置单机软件按钮时发生
        {
            if (e.Button == MouseButtons.Right)
            {
                ExportSelectedSensorsToXlsx();
            }
        }
        private string GetDataTypeString(string dataType, int regLen)//获取数据类型字符串
        {
            if (dataType[0] == 'n')
                return regLen == 1 ? "16位无符号整数" : "32位无符号整数";
            else if (dataType[0] == 'i')
                return regLen == 1 ? "16位有符号整数" : "32位有符号整数";
            else if (dataType[0] == 'f')
            {
                return dataType[1] switch
                {
                    'a' => "浮点数DCBA",
                    'b' => "浮点数CDAB",
                    'c' => "浮点数BADC",
                    'd' => "浮点数ABCD",
                    _ => "未知类型",
                };
            }
            else if (dataType[0] == 'd')
            {
                return dataType[1] switch
                {
                    'a' => "双精度浮点数DCBA",
                    'b' => "双精度浮点数CDAB",
                    'c' => "双精度浮点数BADC",
                    'd' => "双精度浮点数ABCD",
                    _ => "未知类型",
                };
            }
            return "未知类型";
        }

        private void AutoSizeColumnsByContent(ISheet sheet, int columnCount, int maxWidthChars = 60)// 根据内容自动调整列宽
        {
            // 计算每列最长字符串（考虑中文宽度，中文记为2）
            for (int col = 0; col < columnCount; col++)
            {
                int maxLen = 0;
                for (int rowIdx = sheet.FirstRowNum; rowIdx <= sheet.LastRowNum; rowIdx++)
                {
                    IRow? row = sheet.GetRow(rowIdx);
                    if (row == null) continue;
                    ICell? cell = row.GetCell(col);
                    if (cell == null) continue;
                    string text = cell.ToString() ?? "";
                    int length = 0;
                    foreach (char ch in text)
                    {
                        length += ch > 255 ? 2 : 1; // 简单估算：非 ASCII 字符按 2 个宽度计算
                    }
                    if (length > maxLen) maxLen = length;
                }

                // 加一点 padding，限制最大列宽（防止 Excel 无法打开或列超宽）
                int padded = Math.Min(maxLen + 2, maxWidthChars);

                // NPOI 列宽单位是 1/256 个字符宽度
                int width = padded * 256;
                sheet.SetColumnWidth(col, width);
            }
        }
        private void ExportSelectedSensorsToXlsx()
        {
            try
            {
                if (sensorList == null || sensorList.Sensors.Count == 0)
                {
                    MessageBox.Show("没有选中的传感器可导出。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                // 确保目录存在并直接写入指定文件（不弹出对话框）
                string dir = Path.GetFullPath("cachefile");
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

                string filePath = Path.Combine(dir, "传感器点表_selected.xlsx");

                IWorkbook workbook = new XSSFWorkbook();
                ISheet sheet = workbook.CreateSheet("SelectedSensors");

                // 表头
                IRow header = sheet.CreateRow(0);
                string[] headers = new[]
                {
                    "波特率", "9600","N","8","1", "供电电压","11-14V"
                };
                for (int i = 0; i < headers.Length; i++)
                    header.CreateCell(i).SetCellValue(headers[i]);

                IRow header2 = sheet.CreateRow(1);
                string[] headers2 = new[]
                {
                    "设备地址", "名称", "寄存器地址","PLC地址", "寄存器长度",
                    "数据类型","小数位数","单位","上传名称", "读取示例"
                };
                for (int i = 0; i < headers2.Length; i++)
                    header2.CreateCell(i).SetCellValue(headers2[i]);


                // 内容行
                for (int i = 0; i < sensorList.Sensors.Count; i++)
                {
                    Sensor s = sensorList.Sensors[i];
                    IRow row = sheet.CreateRow(i + 2);
                    row.CreateCell(0).SetCellValue(s.DeviceAddress);//设备地址
                    row.CreateCell(1).SetCellValue(s.LEDDisplay.Contains(":") ? s.LEDDisplay.Split(':')[0] : s.LEDDisplay ?? "");//名称
                    row.CreateCell(2).SetCellValue(s.RegisterAddress);//寄存器地址
                    row.CreateCell(3).SetCellValue(s.RegisterAddress + 40001);//PLC地址
                    row.CreateCell(4).SetCellValue(s.RegisterLength);//寄存器长度
                    row.CreateCell(5).SetCellValue(GetDataTypeString(s.DataType, s.RegisterLength));//数据类型
                    row.CreateCell(6).SetCellValue(int.Parse(s.DataType[2].ToString()));
                    row.CreateCell(7).SetCellValue(s.LEDDisplay.Split(':').Length > 1 ? s.LEDDisplay.Split(':')[1] : "");
                    row.CreateCell(8).SetCellValue(s.UploadName ?? "");
                    row.CreateCell(9).SetCellValue(BitConverter.ToString(modbusGenerate(s.DeviceAddress, 0x03,
                        (ushort)s.RegisterAddress, (ushort)s.RegisterLength)).Replace("-", " "));
                }

                // 自动列宽（可选，数量不多时成本可接受）
                AutoSizeColumnsByContent(sheet, headers2.Length, 200);

                // 写入文件（覆盖存在的同名文件）
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    workbook.Write(fs);
                }
                workbook.Close();

                // 复制路径到剪贴板并提示
                try
                {
                    StringCollection files = new StringCollection();
                    files.Add(filePath);
                    Clipboard.SetFileDropList(files);
                }
                catch
                { /* 忽略剪贴板错误 */
                }

                MessageBox.Show($"已保存：{filePath}\n路径已复制到剪贴板（文件列表）。", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"导出失败：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void buttonEmpty4GSensor_Click(object sender, EventArgs e)//单击清除4G传感器按钮时发生
        {
            if (!SerialSendData("{\"cmd\":\"clear485Sensor\"}")) return;
            this.ActiveControl = null;// 清除焦点
        }

        private void buttonEmptyData_Click(object sender, EventArgs e)//单击清除数据按钮时发生
        {
            sendTxt.Text = "";
        }

        private void button4GConfig_Click(object sender, EventArgs e)//单击配置4G传感器按钮时发生
        {
            //{ "cmd":"setSelfAttr","sleepTime":1,"haveLED":255,"describe":"气象监测系统","clientID":"742d4f60-4253-11ef-919f-a9205e35d470",
            //"clientUsr":"XzSnwzOnMysmrJT3108W","clientPwd":" ","sensorTime":0,"senDelay":3,"selFlg":0}

            String jsonString;
            var data = new Dictionary<string, object> { };

            data.Add("cmd", "setSelfAttr");
            data.Add("sleepTime", numericUpDown4GSleep.Value);
            data.Add("haveLED", (comboBox4GLED.Text == "显示" ? 255 : 0));
            if (textBox4GDescribe.Text != "")
                data.Add("describe", textBox4GDescribe.Text);
            if (textBox4GlientID.Text != "")
                data.Add("clientID", textBox4GlientID.Text);
            if (textBox4GClientUsr.Text != "")
                data.Add("clientUsr", textBox4GClientUsr.Text);
            data.Add("sensorTime", numericUpDown4GPoll.Value);
            data.Add("senDelay", numericUpDown4GStabilize.Value);
            data.Add("selFlg", checkBox4GPow.Checked ? 3 : 0);
            jsonString = ObjectToString(data);
            if (!SerialSendData(jsonString)) return;

        }

        private void buttonConfigLED_Click(object sender, EventArgs e)//单击配置LED屏幕按钮时发生
        {
            var data = new Dictionary<string, object>
            {
                ["cmd"] = "setLedAttr",
                ["dispChannel"] = 1,
                ["LEDwidth"] = int.Parse(comboBoxScreenWidth.Text) * 32,
                ["LEDheight"] = int.Parse(comboBoxScreenHeight.Text) * 16,
                ["cellHeight"] = 16,
                ["cellWidth"] = 32,
                ["scan"] = 4,
                ["fontSize"] = 12,
                ["pgSwTime"] = numericUpDownScreenTime.Value
            };
            string jsonString = ObjectToString(data);
            if (!SerialSendData(jsonString)) return;
        }
        private byte[] modbusGenerate(int addr, int func, ushort reg, ushort regLen)//生成modbus数据帧
        {
            byte[] frame = new byte[8];
            frame[0] = (byte)addr;
            frame[1] = (byte)func;
            frame[2] = (byte)(reg >> 8);
            frame[3] = (byte)(reg & 0xFF);
            frame[4] = (byte)(regLen >> 8);
            frame[5] = (byte)(regLen & 0xFF);
            byte[] crc = ModbusUtils.CalculateCRC(frame, 6);
            frame[6] = crc[0];
            frame[7] = crc[1];
            return frame;
        }
        private void buttonReadData_Click(object sender, EventArgs e)//单击读取数据按钮时发生
        {
            if (textBoxSensor.Tag == null)
            {
                MessageBox.Show("请先选择传感器");
                return;
            }

            if (!ushort.TryParse(textBoxRegAddr.Text, out ushort reg))
            {
                MessageBox.Show("寄存器地址无效");
                return;
            }
            if (!byte.TryParse(textBoxRegLen.Text, out byte regLen))
            {
                MessageBox.Show("寄存器长度无效");
                return;
            }
            byte[] frame = modbusGenerate((int)numericUpDown1.Value, 0x03, reg, regLen);

            SerialSendData(frame); // 发送数据帧
        }
        private void comboBoxScreenWidth_TextChanged(object sender, EventArgs e)// 屏幕宽度下拉框文本更改时发生
        {
            int screenWidth = int.TryParse(comboBoxScreenWidth.Text, out int width) ? width : 3;
            int screenHeight = int.TryParse(comboBoxScreenHeight.Text, out int height) ? height : 3;
            label22.Text = (screenWidth * 32).ToString() + "x" + (screenHeight * 16).ToString();
        }

        private void buttonSetAddr_Click(object sender, EventArgs e)//单击设置地址按钮时发生
        {
            if (textBoxSensor.Tag == null)
            {
                MessageBox.Show("请先选择传感器");
                return;
            }
            Sensor? sensor = (Sensor?)textBoxSensor.Tag; // 获取选中行的传感器对象
            if (sensor == null) return; // 如果传感器对象为 null，直接返回

            byte[] frame = modbusGenerate((int)numericUpDownAddr.Value, 0x06,
                (ushort)sensor.AddressRegister, (ushort)numericUpDown1.Value);

            SerialSendData(frame); // 发送数据帧
        }

        private void buttonDel485Sensor_Click(object sender, EventArgs e)//单击删除485传感器按钮时发生
        {
            if (textBoxSensor.Tag == null)
            {
                MessageBox.Show("请先选择要删除的传感器");
                return;
            }
            String jsonString;
            var data = new Dictionary<string, object>
            {
                ["cmd"] = "del485Sensor",
                ["name"] = textBoxUpName.Text // 使用传感器名称作为删除依据
            };
            jsonString = ObjectToString(data);
            if (!SerialSendData(jsonString)) return;
        }

        private void buttoncSetTime_Click(object sender, EventArgs e)//单击设置时间按钮时发生
        {
            if (!isSerialPortOpen())
            {
                MessageBox.Show($"请打开串口");
                return;
            }
            String jsonString;
            var data = new Dictionary<string, object>
            {
                ["cmd"] = "setSysTime",
                ["time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") // 使用当前时间
            };
            jsonString = ObjectToString(data);
            if (!SerialSendData(jsonString)) return;
        }
        private void buttonGrtICCID_Click(object sender, EventArgs e)//单击获取ICCID按钮时发生
        {
            if (!SerialSendData("{\"cmd\": \"getICCID\"}")) return;
            this.ActiveControl = null;// 清除焦点
        }

        private void 配置手持机ToolStripMenuItem_Click(object sender, EventArgs e)//单击配置手持机按钮时发生
        {
            手持机配置 handheldConfig = new 手持机配置();
            if (dataGridView1.Rows.Count == 0)
            {
                MessageBox.Show("请先选择传感器");
                return;
            }
            // 遍历 dataGridView1 中的传感器，将其添加到 handheldConfig 中
            handheldConfig.portConfig.Add(new Dictionary<string, object>
                {
                    { "baud", int.Parse( shouchiBaud.Text) },
                    { "reread", int.Parse(shouchiReread.Text) },
                    { "timeOut", int.Parse(shouchiTimeOut.Text) },
                    { "polling", int.Parse(shouchiPolling.Text) }
                });
            foreach (DataGridViewRow newRow in dataGridView1.Rows)
            {
                Sensor? sensor = (Sensor?)newRow.Tag; // 获取传感器对象
                if (sensor == null) continue; // 如果传感器对象为 null，跳过
                                              // 添加传感器配置到 handheldConfig
                var dat = new Dictionary<string, object>
                {
                    { "cmd", "add485Sensor" },
                    { "addr", sensor.DeviceAddress },
                    { "regAddr", sensor.RegisterAddress },
                    { "dataLen", sensor.RegisterLength },
                    { "valueType", sensor.DataType },
                    { "name", sensor.UploadName },
                    { "describe", sensor.LEDDisplay },
                    {"K", sensor.K == 0.0 ? 1 : sensor.K}
                };
                if (sensor.B != 0.0)
                {
                    dat.Add("B", sensor.B);
                }

                handheldConfig.sensorList.Add(dat);
            }
            // 输出结果JsonSerializer
            try
            {
                // 配置 JSON 序列化选项（缩进）
                var options = new JsonSerializerOptions
                {
                    WriteIndented = true, // 启用缩进
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 可选：避免 Unicode 转义
                };
                // 重新序列化为格式化字符串
                string jsonString = JsonSerializer.Serialize(handheldConfig, options);

                string filePath = Path.GetFullPath("cachefile/CONFIG.txt");
                File.WriteAllText(filePath, jsonString, Encoding.GetEncoding("UTF-8"));
                StringCollection files = new StringCollection();
                files.Add(filePath);
                Clipboard.SetFileDropList(files);
                // 显示提示信息
                MessageBox.Show("转换完成，结果已保存到 CONFIG.txt 文件，并复制到剪切板。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (JsonException ex)
            {
                MessageBox.Show("JSON 序列化错误: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void Form1_DragDrop(object sender, DragEventArgs e)// 拖放文件到窗体时发生
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
                foreach (string file in files)
                {
                    // 这里可以处理每个文件，例如显示路径或读取内容
                    if (Path.GetExtension(file).ToLower() == ".bin")
                    {
                        // 如果是 .bin 文件，进行 AES 解密
                        try
                        {
                            BinFileAesEncryptor.EncryptFileEcbCustomPadding(file, "cachefile/app.bin", aesKey);
                            string filePath = Path.GetFullPath("cachefile/app.bin");
                            StringCollection cpyfiles = new StringCollection();
                            cpyfiles.Add(filePath);
                            Clipboard.SetFileDropList(cpyfiles);
                            // 显示提示信息
                            MessageBox.Show("加密成功，结果已保存到 app.bin 文件，并复制到剪切板。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("解密失败: " + ex.Message);
                        }
                    }
                }
            }
        }

        private void Form1_DragEnter(object sender, DragEventArgs e)// 拖放文件进入窗体时发生
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }
    }
}


